package com.dman.multi.core;

import java.net.URL;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import org.apache.pivot.collections.ArrayList;
import org.apache.pivot.collections.HashMap;
import org.apache.pivot.collections.List;
import org.apache.pivot.collections.Map;
import org.apache.pivot.serialization.SerializationException;
import org.apache.pivot.util.concurrent.TaskExecutionException;
import org.apache.pivot.wtk.BoxPane;
import org.apache.pivot.wtk.Label;
import org.apache.pivot.wtk.Meter;
import org.apache.pivot.wtk.Orientation;
import org.apache.pivot.wtk.TableView;
import org.apache.pivot.wtk.media.Image;


public class UIThread implements Runnable {
	
	private List<Download> downloadList;
	private TableView downloadTable;
	private Map<Integer, String> expToAbbr;
	private Map<Download, BoxPane> downloadToBoxpane;
	private SimpleDateFormat sdf;
	
	public UIThread(List<Download> downloadList, TableView downloadTable) {
		this.downloadList = downloadList;
		this.downloadTable = downloadTable;
		expToAbbr = new HashMap<Integer, String>();
		expToAbbr.put(0, " B");
		expToAbbr.put(1, " KB");
		expToAbbr.put(2, " MB");
		expToAbbr.put(3, " GB");
		expToAbbr.put(4, " TB");
		downloadToBoxpane = new HashMap<Download, BoxPane>();
		sdf = new SimpleDateFormat("dd/MMM/yyyy HH:mm");
	}

	@Override
	public void run() {
		List<DownloadView> dvList = null;
		while(true){
			dvList = new ArrayList<DownloadView>();
			try {
				int selectedIndex = downloadTable.getSelectedIndex();
				synchronized(downloadList){
					for(Download d: downloadList){
						if(d.isVisible()){
							DownloadView dv = new DownloadView();
							dv.setDownloadState(getDownloadState(d));
							dv.setFileName(getFileName(d));
							dv.setSize(getSize(d));
							dv.setPercentComplete(getPercentComplete(d));
							dv.setDownloadSpeed(getDownloadSpeed(d));
							dv.setSections(getSections(d));
							dv.setStartDate(getStartDate(d));
							dv.setCompleteDate(getCompleteDate(d));
							dvList.add(dv);
						}
					}
				}
				downloadTable.setTableData(dvList);
				if(selectedIndex < dvList.getLength())
					downloadTable.setSelectedIndex(selectedIndex);
				Thread.sleep(1000);
			} catch (InterruptedException e) {}
		}
	}

	public Image getDownloadState(Download d){
		String location = "../ui/";
		Image img = null;
		switch(d.getDownloadState()){
		case PAUSED:
			location += "stop-med.png";
			break;
		case RUNNING:
			location += "down-med.png";
			break;
		case COMPLETE:
			location += "done-med.png";
			break;
		default:
			location += "schedule-med.png";
			break;
		}
		
		try {
			URL loc = UIThread.class.getResource(location);
			img = Image.load(loc);
		} catch (TaskExecutionException e) {
			e.printStackTrace();
		}
		
		return img;
	}
	
	public String getFileName(Download d){
		return d.getFileName();
	}
	
	public String getSize(Download d){
		double size = d.getSize();
		int units = 0;
		int exponent = 1<<10;
		String str = "NA";
		if(size >= 0){
			while(size > exponent){
				size /= exponent;
				++units;
			}
			long lsize = Math.round(size * 10);
			str = lsize / 10 + "." + lsize % 10 + expToAbbr.get(units);
		}
		
		return str;
	}
	
	private String getFormattedEta(Download d){
		
		double speed = d.getDownloadSpeed();
		String eta = "ETA: ";
		double pcRemain = 100 - d.getPercentComplete();
		double size = d.getSize();
		long etaSeconds = (long) (pcRemain * size / 100 / speed);
		int count = 0;
		long remainingSecs = etaSeconds;
		long secondsInYear = 360 * 24 * 60 * 60;
		
		if(secondsInYear < remainingSecs || d.getSize() < 0)
			return eta + DecimalFormatSymbols.getInstance().getInfinity();
		
		if(remainingSecs > 86400 && count < 2){
			eta += remainingSecs / 86400 + "d ";
			remainingSecs = remainingSecs % 86400;
			++count;
		}
		
		if(remainingSecs > 3600 && count < 2){
			eta += remainingSecs / 3600 + "h ";
			remainingSecs = remainingSecs % 3600;
			++count;
		}
		
		if(remainingSecs > 60 && count < 2){
			eta += remainingSecs / 60 + "m ";
			remainingSecs = remainingSecs % 60;
			++count;
		}
		
		if(count < 2){
			eta += remainingSecs + "s ";
			remainingSecs = remainingSecs % 60;
			++count;
		}
		
		return eta;
	}
	
	public BoxPane getPercentComplete(Download d){
		BoxPane boxPane = downloadToBoxpane.get(d);
		double pc = d.getPercentComplete();
		
		// check for chunked transfer 
		if(pc < 0){
			pc = 0;
			if(d.isDownloadComplete())
				pc = 100;
		}
		
		// format the percentage
		long lpc = Math.round(pc * 10);
		String text = lpc / 10 + "." + lpc % 10 + "%";
		Meter meter = null;
		Label label = null;
		if(boxPane == null){
			boxPane = new BoxPane(Orientation.VERTICAL);
			meter = new Meter();
			label = new Label();
			boxPane.add(meter);
			boxPane.add(label);
			try {
				boxPane.setStyles("{horizontalAlignment: 'center', verticalAlignment: 'center'}");
			} catch (SerializationException e) {}
			downloadToBoxpane.put(d, boxPane);
		}
		
		if(meter == null)
			meter = (Meter) boxPane.get(0);
		if(label == null)
			label = (Label) boxPane.get(1);
		
		pc = (pc > 100)?100:pc;
		meter.setPercentage(pc / 100);
		meter.setText(text);
		label.setText(getFormattedEta(d));
		
		return boxPane;
	}
	
	public String getDownloadSpeed(Download d){
		double speed = d.getDownloadSpeed();
		long pc = (long) d.getPercentComplete();
		int units = 0;
		int exponent = 1<<10;
		while(speed > exponent){
			speed /= exponent;
			++units;
		}
		long lspeed = Math.round(speed * 10);
		String str = lspeed / 10 + "." + lspeed % 10;
		if(pc == 100 || d.isDownloadComplete()){
			str = "0.0";
			units = 0;
		}
		
		str += expToAbbr.get(units) + "/s";
		
		return str;
	}
	
	public String getSections(Download d){
		return d.getSections();
	}
	
	public String getStartDate(Download d){
		Calendar cal = d.getStartDate();
		Date date = new Date(cal.getTimeInMillis());
		String strDate = sdf.format(date);
		return strDate;
	}
	
	public String getCompleteDate(Download d){
		Calendar cal = d.getCompleteDate();
		String strDate = null;
		if(cal != null){
			Date date = new Date(cal.getTimeInMillis());
			strDate = sdf.format(date);
		}
		
		return strDate;
	}
}
